;; ****************************************************************************
;; *                             PWM Driver  v2.00                            *
;; *                                                                          *
;; *               Fully deterministic and Cycle-Accurate Version             *
;; *                                                                          *
;; *                           Accepts fast updates                           *
;; *                                                                          *
;; * Operates 6 bi-directional joints, PWM f=250Hz w/adjust. pulse width 0-99 *
;; *                             				              *
;; ****************************************************************************

	list		p=16F84A		; define processor
	#include	<p16f84a.inc>		; processor-specific defs
	
	__CONFIG	_CP_OFF & _WDT_OFF & _PWRTE_ON & _HS_OSC

	;; ******************************************************************
	;; Electric Connections

	;; Header Pinout (DIP 2x8 male):
	;; [pin #] [old pin name]/[PIC16F84 pin name]/[joint and value]
	;;   -----------------------------------
	;;  /                                   \
	;; | 1 A0/RA0/JD[5]=0   9 GND            |
	;;   2 A1/RA1/JD[5]=1  10 D4/RB4/JD[1]=0 |
	;;   3 A2/RA2/JD[4]=0  11 D5/RB5/JD[1]=1 |
	;; | 4 A3/RA3/JD[4]=1  12 D6/RB6/JD[0]=0 |
	;; | 5 D0/RA4/JD[3]=0  13 D7/RB7/JD[0]=1 |
	;;   6 D1/RB1/JD[3]=1  14 NC             |
	;;   7 D2/RB2/JD[2]=0  15 NC             |
	;; | 8 D2/RB3/JD[2]=1  16 VCC (+5V)      |
	;;  \                                   /
	;;   -----------------------------------
	;; ^
	;; \ left side of shroud in contact with PCB (and has keying slots)
	
	;; Port Tristates
	#define		trisPortA	B'00000000' ; All output
	#define		trisPortB	B'00000001' ; All output except RX

	;; I/O Pin - RS-232 protocol, 9600 baud, 8 bits, no parity
	;; Command Format:
	;; !XaAAbBBcCCdDDeEEfFF
	;; where X is device address, a-f are directions ('+' or '-')
	;; and AA-FF are integers 0..99 for PWM pulse width
	#define		SERIAL_RX	PORTB, 0

	;; 12 PWM channels
	#define		CHANNEL_A0	PortB_Shadow, 6	; pin 12 of header
	#define		CHANNEL_A1	PortB_Shadow, 7	; pin 13 of header
	#define		CHANNEL_B0	PortB_Shadow, 4	; pin 10 of header
	#define		CHANNEL_B1	PortB_Shadow, 5	; pin 11 of header
	#define		CHANNEL_C0	PortB_Shadow, 2	; pin 7 of header
	#define		CHANNEL_C1	PortB_Shadow, 3	; pin 8 of header
	#define		CHANNEL_D0	PortA_Shadow, 4	; pin 5 of header
	#define		CHANNEL_D1	PortB_Shadow, 1	; pin 6 of header
	#define		CHANNEL_E0	PortA_Shadow, 2	; pin 3 of header
	#define		CHANNEL_E1	PortA_Shadow, 3	; pin 4 of header
	#define		CHANNEL_F0	PortA_Shadow, 0	; pin 1 of header
	#define		CHANNEL_F1	PortA_Shadow, 1	; pin 2 of header
	
	;; ******************************************************************
	;; PWM Phase Shifts - minimize simultaneous rising edge transitions

	#define		A_PHASE_DELTA	D'0'
	#define		B_PHASE_DELTA	D'16'
	#define		C_PHASE_DELTA	D'32'
	#define		D_PHASE_DELTA	D'48'
	#define		E_PHASE_DELTA	D'64'
	#define		F_PHASE_DELTA	D'80'
	
	;; ******************************************************************
	;; Control Command Format

	#define		BUS_ADDRESS	'L'      ; We are left arm
	
	;; ******************************************************************
	;; Calibration Values and Magic Numbers

	#define		MAXTICKS	D'100'   ; ticks per period
	
	;; ******************************************************************


;; ******************************************************************
;; Useful Macros

;; Check for page boundary crossing
no_page_cross	macro	start, finish
 		if ((high start) - (high finish)) != 0
 			ERROR "Table crossed page boundary!"
 		endif
 		endm

;; Clear port shadow registers
clr_shadows	macro
 		clrf	PortA_Shadow
		clrf	PortB_Shadow
		bsf	PortB_Shadow, 0	; prevent spurious RBO interrupt
 		endm

;; Update registers from shadows to set outputs
shadows_live	macro
 		movf	PortA_Shadow, W	; load Port A Shadow
		movwf	PORTA		; update Port A
		movf	PortB_Shadow, W	; load Port B Shadow
		movwf	PORTB		; update Port B
 		endm

;; Save complete CPU state
save_state	macro
		movwf   SaveW		; save off current W register contents
		movf	STATUS, W       ; move status register into W register
		movwf	SaveStatus      ; save off contents of STATUS register
; 		movf	FSR, W		; move FSR into W
; 		movwf	SaveFSR		; save old FSR
		endm

;; Restore complete CPU state
restore_state	macro
; 		movf	SaveFSR, W	; get saved FSR
; 		movwf	FSR		; restore FSR
		movf    SaveStatus, W   ; retrieve copy of STATUS register
		movwf	STATUS          ; restore STATUS register contents
		swapf   SaveW, F
		swapf   SaveW, W        ; restore W register contents
		endm


;; ******************************************************************
	
	;; ******************************************************************
	;; Variables
	cblock		0x0c
	;; Port Shadows
		PortA_Shadow	; Shadow to prevent hazard
		PortB_Shadow	; 
	;; For interrupt handler state save/restore
		SaveW 		; save/restore W register in interrupt handler
		SaveStatus 	; save/restore status register
;; 		SaveFSR		; save/restore FSR
		NextInt		; contents of INTCON register for next interrupt
	;; For serial I/O
		BitsLeft	; bits remaining in incoming byte
		ByteBuffer	; single-byte lexer buffer
		LEAP_USEC   ; boolean to keep track of leap tick
		COMM_FLAGS  ; comm. flags
		COMM_BUFFER ; single-byte receive buffer
	;; Values from Control Packet as it is received
		A_PW		; Pulse width of Channel A - 0..99
		B_PW		; Pulse width of Channel B - 0..99
		C_PW		; Pulse width of Channel C - 0..99
		D_PW		; Pulse width of Channel D - 0..99
		E_PW		; Pulse width of Channel E - 0..99
		F_PW		; Pulse width of Channel F - 0..99
		ValveDirs	; Valve direction flags
	;; copy of above used to generate PWM counters
		ValveStates	; Valve direction flags
	;; Control Packet Reception
		StateMachPos	; Position in state machine
		BitMachState   ; Position in bit state machine
		CurrentDirBit	; direction bit to scan
		CurrentReg	; FSR value to update
	;; PWM settings
		PWM_TIME	; Current PWM Time - 0.00004 seconds apart
		; Time T of rise or fall of waveform, in units of
		; 1/(250Hz * 100 divs) seconds from start of period
		; valid input range: 0..99 --> stored as 1..100
		A_RISE		; channel rise times
		B_RISE
		C_RISE
		D_RISE
		E_RISE
		F_RISE
		A_FALL		; channel fall times
		B_FALL
		C_FALL
		D_FALL
		E_FALL
		F_FALL
		; rise and fall times from newly captured packet
		NEW_A_RISE	; channel rise times
		NEW_B_RISE
		NEW_C_RISE
		NEW_D_RISE
		NEW_E_RISE
		NEW_F_RISE
		NEW_A_FALL	; channel fall times
		NEW_B_FALL
		NEW_C_FALL
		NEW_D_FALL
		NEW_E_FALL
		NEW_F_FALL
		NEW_VALVES
	endc

	cblock		0
		RX_SHADOW  ; receive buffer
		BYTE_READY ; a byte must be interpreted
		NEW_OUTPUTS ; time to recalculate outputs
	endc

	cblock		0	; Valve Flags
		A_DIR		;
		B_DIR		;
		C_DIR		; Joint direction control (0 = '-', 1 = '+')
		D_DIR		;
		E_DIR		;
		F_DIR		;
	endc
	
	;; ******************************************************************
	ORG	0x000		; processor reset vector
 	goto	init		; go to beginning of program
	ORG	0x004		; interrupt vector location
	;; Interrupt Service Routine - every 260.5 ticks
	save_state		; Save CPU State
	; add leap tick
	movlw	D'1'
	comf	LEAP_USEC, F
	skpz
	addlw	D'1'
	subwf	TMR0, F


	decfsz	A_RISE, F	; update status of Channel A
	goto	$+3
	call	ch_a_rise
	goto	$+2
	call	null_event
	decfsz	A_FALL, F
	goto	$+3
	call	ch_a_fall
	goto	$+2
	call	null_event
	decfsz	B_RISE, F	; update status of Channel B
	goto	$+3
	call	ch_b_rise
	goto	$+2
	call	null_event
	decfsz	B_FALL, F
	goto	$+3
	call	ch_b_fall
	goto	$+2
	call	null_event
	decfsz	C_RISE, F	; update status of Channel C
	goto	$+3
	call	ch_c_rise
	goto	$+2
	call	null_event
	decfsz	C_FALL, F
	goto	$+3
	call	ch_c_fall
	goto	$+2
	call	null_event
	decfsz	D_RISE, F	; update status of Channel D
	goto	$+3
	call	ch_d_rise
	goto	$+2
	call	null_event
	decfsz	D_FALL, F
	goto	$+3
	call	ch_d_fall
	goto	$+2
	call	null_event
	decfsz	E_RISE, F	; update status of Channel E
	goto	$+3
	call	ch_e_rise
	goto	$+2
	call	null_event
	decfsz	E_FALL, F
	goto	$+3
	call	ch_e_fall
	goto	$+2
	call	null_event
	decfsz	F_RISE, F	; update status of Channel F
	goto	$+3
	call	ch_f_rise
	goto	$+2
	call	null_event
	decfsz	F_FALL, F
	goto	$+3
	call	ch_f_fall
	goto	$+2
	call	null_event
	shadows_live		; update ports from shadows
	decfsz	PWM_TIME, F	; 100 divs elapsed?
	goto	in_period
	;; must begin new period
	movlw	MAXTICKS	; pwm tick counter
	movwf	PWM_TIME
	movf	NEW_A_RISE, W
	movwf	A_RISE
	movf	NEW_B_RISE, W
	movwf	B_RISE
	movf	NEW_C_RISE, W
	movwf	C_RISE
	movf	NEW_D_RISE, W
	movwf	D_RISE
	movf	NEW_E_RISE, W
	movwf	E_RISE
	movf	NEW_F_RISE, W
	movwf	F_RISE
	movf	NEW_A_FALL, W
	movwf	A_FALL
	movf	NEW_B_FALL, W
	movwf	B_FALL
	movf	NEW_C_FALL, W
	movwf	C_FALL
	movf	NEW_D_FALL, W
	movwf	D_FALL
	movf	NEW_E_FALL, W
	movwf	E_FALL
	movf	NEW_F_FALL, W
	movwf	F_FALL
	movf	NEW_VALVES, W
	movwf	ValveStates


	comf	ValveStates, F	; switch off reversed outputs
	call	ch_a_fall
	call	ch_b_fall
	call	ch_c_fall
	call	ch_d_fall
	call	ch_e_fall
	call	ch_f_fall
	comf	ValveStates, F

	
	goto	Skip_Ballast
in_period
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop		
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop

Skip_Ballast


; scan RX line - only here, so we will be in phase
	bcf	COMM_FLAGS, RX_SHADOW
	btfsc	SERIAL_RX
	bsf	COMM_FLAGS, RX_SHADOW
	call	bit_machine 	; next state will end up in W
	movwf	BitMachState	; update machine state

	btfsc	COMM_FLAGS, NEW_OUTPUTS
	call	update_waveforms

	bcf	INTCON, T0IF
	restore_state		; Restore CPU State
	retfie                  ; return from interrupt

bit_machine
	movlw  	high(bit_state_table)
	movwf  	PCLATH    
	movf   	BitMachState, W	; load current position in state machine
	addlw  	bit_state_table
	skpnc
	incf   	PCLATH, F
	movwf  	PCL
bit_state_table
	goto	BitMachState_0		; waiting for start bit
	goto	BitMachState_1		; wait state
	goto	BitMachState_2		; get data bit
	goto	BitMachState_3		; accepting state and rollover

BitMachState_0 ; wait for start bit
	btfsc	COMM_FLAGS, RX_SHADOW
	retlw D'0' ; no start bit yet
	; received start bit
	clrf	COMM_BUFFER	; clear receive buffer
	movlw	D'8'		; there will be eight!
	movwf	BitsLeft	; bits left to receive
	retlw D'1' ; next state: wait state
BitMachState_1 ; wait state
	retlw D'2'
BitMachState_2 ; get data bit
	bcf	STATUS, C
	btfsc	COMM_FLAGS, RX_SHADOW ; read one bit
	bsf	STATUS, C
	rrf	COMM_BUFFER, F	; shift bit into buffer
	decfsz	BitsLeft, F
	retlw 	D'1' ; more data bits will appear
	retlw 	D'3' ; or not... go to accepting state
BitMachState_3 ; accepting state and rollover
	movf	COMM_BUFFER, W
	movwf	ByteBuffer
	bsf	COMM_FLAGS, BYTE_READY
	retlw 	D'0'
	;; End of Interrupt Service Routine
	;; ******************************************************************


; nothing happens
null_event
	nop
	nop
	nop
	nop
	nop
	return

	;; falling of channels
ch_a_fall
	btfsc	ValveStates, A_DIR
	goto	$+4
	nop
	bcf	CHANNEL_A0
	return
	bcf	CHANNEL_A1
	return
ch_b_fall
	btfsc	ValveStates, B_DIR
	goto	$+4
	nop
	bcf	CHANNEL_B0
	return
	bcf	CHANNEL_B1
	return
ch_c_fall
	btfsc	ValveStates, C_DIR
	goto	$+4
	nop	
	bcf	CHANNEL_C0
	return
	bcf	CHANNEL_C1
	return
ch_d_fall
	btfsc	ValveStates, D_DIR
	goto	$+4
	nop
	bcf	CHANNEL_D0
	return
	bcf	CHANNEL_D1
	return
ch_e_fall
	btfsc	ValveStates, E_DIR
	goto	$+4
	nop	
	bcf	CHANNEL_E0
	return
	bcf	CHANNEL_E1
	return
ch_f_fall
	btfsc	ValveStates, F_DIR
	goto	$+4
	nop
	bcf	CHANNEL_F0
	return
	bcf	CHANNEL_F1
	return
	
	;; rising of channels
ch_a_rise
	btfsc	ValveStates, A_DIR
	goto	$+4
	nop	
	bsf	CHANNEL_A0
	return
	bsf	CHANNEL_A1
	return
ch_b_rise
	btfsc	ValveStates, B_DIR
	goto	$+4
	nop
	bsf	CHANNEL_B0
	return
	bsf	CHANNEL_B1
	return
ch_c_rise
	btfsc	ValveStates, C_DIR
	goto	$+4
	nop
	bsf	CHANNEL_C0
	return
	bsf	CHANNEL_C1
	return
ch_d_rise
	btfsc	ValveStates, D_DIR
	goto	$+4
	nop
	bsf	CHANNEL_D0
	return
	bsf	CHANNEL_D1
	return
ch_e_rise
	btfsc	ValveStates, E_DIR
	goto	$+4
	nop
	bsf	CHANNEL_E0
	return
	bsf	CHANNEL_E1
	return
ch_f_rise
	btfsc	ValveStates, F_DIR
	goto	$+4
	nop
	bsf	CHANNEL_F0
	return
	bsf	CHANNEL_F1
	return


update_waveforms
	;; generate PWM counter values from pulse width values

	bcf	COMM_FLAGS, NEW_OUTPUTS ; clear flag

	movlw	A_PHASE_DELTA	; calculate Channel A rise/fall times
	movwf	NEW_A_RISE
	movwf	NEW_A_FALL
	movf	A_PW, W
	addwf	NEW_A_FALL, F
	movlw	MAXTICKS
	subwf	NEW_A_FALL, W
	skpnc
	movwf	NEW_A_FALL
	incf	NEW_A_RISE, F
	incf	NEW_A_FALL, F
	
	movlw	B_PHASE_DELTA	; calculate Channel B rise/fall times
	movwf	NEW_B_RISE
	movwf	NEW_B_FALL
	movf	B_PW, W
	addwf	NEW_B_FALL, F
	movlw	MAXTICKS
	subwf	NEW_B_FALL, W
	skpnc
	movwf	NEW_B_FALL
	incf	NEW_B_RISE, F	
	incf	NEW_B_FALL, F
	
	movlw	C_PHASE_DELTA	; calculate Channel C rise/fall times
	movwf	NEW_C_RISE
	movwf	NEW_C_FALL
	movf	C_PW, W
	addwf	NEW_C_FALL, F
	movlw	MAXTICKS
	subwf	NEW_C_FALL, W
	skpnc
	movwf	NEW_C_FALL
	incf	NEW_C_RISE, F
	incf	NEW_C_FALL, F
	
	movlw	D_PHASE_DELTA	; calculate Channel D rise/fall times
	movwf	NEW_D_RISE
	movwf	NEW_D_FALL
	movf	D_PW, W
	addwf	NEW_D_FALL, F
	movlw	MAXTICKS
	subwf	NEW_D_FALL, W
	skpnc
	movwf	NEW_D_FALL	
	incf	NEW_D_RISE, F
	incf	NEW_D_FALL, F
	
	movlw	E_PHASE_DELTA	; calculate Channel E rise/fall times
	movwf	NEW_E_RISE
	movwf	NEW_E_FALL
	movf	E_PW, W
	addwf	NEW_E_FALL, F
	movlw	MAXTICKS
	subwf	NEW_E_FALL, W
	skpnc
	movwf	NEW_E_FALL
	incf	NEW_E_RISE, F
	incf	NEW_E_FALL, F
	
	movlw	F_PHASE_DELTA	; calculate Channel F rise/fall times
	movwf	NEW_F_RISE
	movwf	NEW_F_FALL
	movf	F_PW, W
	addwf	NEW_F_FALL, F
	movlw	MAXTICKS
	subwf	NEW_F_FALL, W
	skpnc
	movwf	NEW_F_FALL
	incf	NEW_F_RISE, F
	incf	NEW_F_FALL, F	

	movf	ValveDirs, W	; set active valve directions
	movwf	NEW_VALVES

	return

	
	;; ******************************************************************
init
	;; Initialize I/O ports
	bcf	INTCON, GIE	; disable interrupts
	bcf	STATUS, RP0	; set bank zero
	clrf	PORTA		; clear port A
	clrf	PORTB		; clear port B
	bsf	STATUS, RP0	; set bank one
	movlw	trisPortA	; load port A tristates into W
	movwf	TRISA		; set port A tristates
	movlw	trisPortB	; load port B tristates into W
	movwf	TRISB		; set port B tristates
	;; Set up timer
	clrf	OPTION_REG	;
	bsf	OPTION_REG, PSA	; timer: turn prescaler OFF
	bcf	STATUS, RP0	; set bank zero
	;; Initialize interrupts
	clrf	INTCON
	bsf	INTCON, T0IE	; Timer overflow interrupt enabled
	;; Initialize counters
	clrf	StateMachPos	; reset State Machine for control packets
	clrf	BitMachState	; reset State Machine for bits
	clrf	COMM_FLAGS
	clr_shadows		; blank output shadow registers

	movlw	D'1'
	movwf	NEW_A_FALL
	movwf	NEW_A_RISE
	movwf	NEW_B_FALL
	movwf	NEW_B_RISE
	movwf	NEW_C_FALL
	movwf	NEW_C_RISE
	movwf	NEW_D_FALL
	movwf	NEW_D_RISE
	movwf	NEW_E_FALL
	movwf	NEW_E_RISE
	movwf	NEW_F_FALL
	movwf	NEW_F_RISE

	movlw	D'1'
	movwf	PWM_TIME

	;; Let the fun begin
	bsf	INTCON, GIE	; enable interrupts (and thus PWM output)
	goto	receive_byte	; wait for commands...


receive_byte
	btfss 	COMM_FLAGS, BYTE_READY
	goto 	receive_byte
	bcf 	COMM_FLAGS, BYTE_READY
	call 	state_machine
	movwf	StateMachPos	; update machine state
	goto 	receive_byte


	;; State Machine for processing control packet - evaluate ByteBuffer
state_machine
	movf	CurrentReg, W	; pwm value to update
	movwf	FSR		; make target
	movlw  high(msg_state_table)
	movwf  PCLATH
	movf   StateMachPos, W	; load current position in state machine
	addlw  msg_state_table
	skpnc
	incf   PCLATH, F
	movwf  PCL
msg_state_table			; !XaAAbBBcCCdDDeEEfFF
;	addwf	PCL, F		; jump to current state
	goto	State_0		; '!' start byte
	goto	State_1		; address byte
	goto	State_2		; 'a' direction
	goto	State_3		; A upper dec
	goto	State_4		; A lower dec
	goto	State_5		; 'b' direction
	goto	State_6		; B upper dec
	goto	State_7		; B lower dec
	goto	State_8		; 'c' direction
	goto	State_9		; C upper dec
	goto	State_10	; C lower dec
	goto	State_11	; 'd' direction
	goto	State_12	; D upper dec
	goto	State_13	; D lower dec
	goto	State_14	; 'e' direction
	goto	State_15	; E upper dec
	goto	State_16	; E lower dec
	goto	State_17	; 'f' direction
	goto	State_18	; F upper dec
	goto	State_19	; F lower dec <--- happy fun state
end_msg_state_table
	no_page_cross	msg_state_table, end_msg_state_table

State_0	 ; '!' marks start of control packet
	movlw	'!'
	subwf	ByteBuffer, W
	skpz
	retlw	D'0'		; nooooo....
	retlw	D'1'		; we can go to S1
State_1	 ; address byte
	movlw	BUS_ADDRESS	; are they talking to -me-?!?
	subwf	ByteBuffer, W
	skpz
	goto	State_0		; account for repeated '!'
	retlw	D'2'		; we can go to S2
State_2	 ; 'a' direction
	clrf	ValveDirs	; initially all '-'
	clrf	CurrentDirBit
	bsf	CurrentDirBit, A_DIR ; direction to set - 'a'
 	movlw	A_PW-1		; current destination - 'A' PW value
 	movwf	CurrentReg	; target for value
State_5	 ; 'b' direction
State_8	 ; 'c' direction
State_11 ; 'd' direction
State_14 ; 'e' direction
State_17 ; 'f' direction
	movf	ByteBuffer, W
	sublw	'-'
	skpnz
	goto	have_minus	; direction byte is '-'
	movf	ByteBuffer, W
	sublw	'+'
	skpnz
	goto	have_plus	; direction byte is '+'
	goto	State_0		; neither? nooooo....
have_plus
	movf	CurrentDirBit, W; mask
	iorwf	ValveDirs, F	; set current
have_minus			; don't set bit
	bcf	STATUS, C	; 
	rlf	CurrentDirBit, F; advance direction bit to set
	incf	CurrentReg, F	; advance destination for value
	incf	StateMachPos, W	; next position
	return
State_3	 ; A tens digit
State_6	 ; B tens digit
State_9	 ; C tens digit
State_12 ; D tens digit
State_15 ; E tens digit
State_18 ; F tens digit
	movf	ByteBuffer, W	; load ascii char
	andlw	0xF		; convert to 0-9
	movwf	INDF		; current tens digit
	addwf	INDF, F		; x*=2
	rlf	INDF, F		; x*=2
	addwf	INDF, F		; x+=x
	rlf	INDF, F		; x*=2
	goto	end_digit	; x == char*10
State_4	 ; A ones digit
State_7	 ; B ones digit
State_10 ; C ones digit
State_13 ; D ones digit
State_16 ; E ones digit
State_19 ; F ones digit
	movf	ByteBuffer, W	; load ascii char
	andlw	0xF		; convert to 0-9
	addwf	INDF, F		; add ones digit to total
end_digit
	;; check if it was really an ascii digit
	movf	ByteBuffer, W
	addlw	(0xFF - '9') & 0xFF
        addlw	(('9' - '0') + 1) & 0xFF
	skpc
	goto	State_0		; nooooo... all in vain!
	;; ok
	movlw	D'19'		; check if final state
	subwf	StateMachPos, W
	skpnz
	goto	accepting_state
	incf	StateMachPos, W	; no? transition to next state
	return
accepting_state			; process captured values
	bsf	COMM_FLAGS, NEW_OUTPUTS ; trigger recalculation on next pwm period
	retlw	D'0'		; back to starting state, listen for next packet
	
	END

	